package com.inspection.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.inspection.constant.EventApproveStatusEnum;
import com.inspection.constant.YesNoEnum;
import com.inspection.dao.*;
import com.inspection.entity.*;
import com.inspection.model.dto.*;
import com.inspection.model.excel.InspectionEventExcelVO;
import com.inspection.service.InspectionEventService;
import com.inspection.support.AssertUtils;
import com.inspection.support.ExcelUtils;
import com.inspection.support.PageHelper;
import com.inspection.support.SortHelper;
import com.inspection.support.model.BusinessBaseException;
import com.inspection.support.model.KeyValuePair;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class InspectionEventServiceImpl implements InspectionEventService {
    static Sort sort = new Sort(Sort.Direction.DESC, "id");


    @Autowired
    private InspectionEventDao inspectionEventDao;
    @Autowired
    private InspectionDeptRegulationDao inspectionDeptRegulationDao;
    @Autowired
    private InspectionRegulationDao inspectionRegulationDao;

    @Autowired
    private InspectionBranchDao inspectionBranchDao;


    @Autowired
    private InspectionDepartmentDao inspectionDepartmentDao;
    @Autowired
    private InspectionEventDeptRelationDao inspectionEventDeptRelationDao;
    @Autowired
    private InspectionEventCorrectDao inspectionEventCorrectDao;

    @Override
    public List<InspectionEventDO> queryEvent(InspectionEventQueryDTO query) {
        return inspectionEventDao.findAll(sort);
    }

//    @Override
//    public Page<InspectionEventDO> pageEvent(InspectionEventQueryDTO page) {
//        Sort sort = new Sort(Sort.Direction.DESC, "id");
//        PageHelper check = PageHelper.check(page.getPageNo(), page.getPageSize());
//        Pageable pageable = PageRequest.of(check.getOffset(), check.getPageSize(), sort);
//        Page<InspectionEventDO> eventPage = inspectionEventDao.findAll(pageable);
//
//        //对字段进行额外的处理
//
//        //被考核支部信息
//        List<Long> branchIdList = eventPage.getContent().stream().map(e -> e.getInspectBranch()).collect(Collectors.toList());
//        List<InspectionBranchDO> branches = inspectionBranchDao.findAllById(branchIdList);
//        Map<Long, InspectionBranchDO> branchMap = branches.stream().collect(Collectors.toMap(InspectionBranchDO::getId, branch -> branch,(v1,v2)->v1));
//
//        //部門
//        //执行的部门信息
//        Set<Long> deptIdsFinal=new HashSet<>();
//        List<Long> exeDeptIds = eventPage.getContent().stream().map(e -> e.getExecuteDept()).collect(Collectors.toList());
//        deptIdsFinal.addAll(exeDeptIds);
//        //被考核部门
//        for (InspectionEventDO eventDO : eventPage.getContent()) {
//            InspectionEventDeptRelationDO eventDeptParam = new InspectionEventDeptRelationDO();
//            eventDeptParam.setInspectionEventId(eventDO.getId());
//            List<InspectionEventDeptRelationDO> all = inspectionEventDeptRelationDao.findAll(Example.of(eventDeptParam));
//            if(!CollectionUtils.isEmpty(all)){
//              List<Long>  tempDept = all.stream().map(r -> r.getInspectionDeptId()).collect(Collectors.toList());
//                deptIdsFinal.addAll(tempDept);
//                eventDO.setInspectDeptList(tempDept);//顺便塞回去 等会用
//            }
//        }
//
//        List<InspectionDepartmentDO> departments = inspectionDepartmentDao.findAllById(deptIdsFinal);
//        Map<Long, InspectionDepartmentDO> deptMap = departments.stream().collect(Collectors.toMap(InspectionDepartmentDO::getId, dept -> dept,(v1,v2)->v1));
//
//
//        //考核条例的名称
//        List<Long> regulationIds = eventPage.getContent().stream().map(e -> e.getRegulationId()).collect(Collectors.toList());
//        List<InspectionRegulationDO> regulations = inspectionRegulationDao.findAllById(regulationIds);//這裡不用判斷是否刪除
//        Map<Long, InspectionRegulationDO> regulationMap = regulations.stream().collect(Collectors.toMap(InspectionRegulationDO::getId, regulation -> regulation,(v1,v2)->v1));
//
//
//
//        for (InspectionEventDO event : eventPage.getContent()) {
//            //被考核支部
//            InspectionBranchDO branch = branchMap.get(event.getInspectBranch());
//            if (Objects.nonNull(branch)) {
//                event.setInspectBranchName(branch.getBranchName());
//            }
//            //被考核部门 是多个的
//            List<Long> inspectDeptList = event.getInspectDeptList();
//            //名字进行拼接
//            List<String> inspectDeptNames=new ArrayList<>();
//            for (Long deptId : inspectDeptList) {
//                InspectionDepartmentDO department = deptMap.get(deptId);
//                if (Objects.nonNull(department)) {
//                    inspectDeptNames.add(department.getDeptName());
//                }
//            }
//            if(!CollectionUtils.isEmpty(inspectDeptNames)){
//                //多個被考核部門的名字
//                event.setInspectDeptName(inspectDeptNames.stream().collect(Collectors.joining(",")));
//            }
//
//
//            //考核部门
//            InspectionDepartmentDO exeDepartment = deptMap.get(event.getExecuteDept());
//            if (Objects.nonNull(exeDepartment)) {
//                event.setExecuteDeptName(exeDepartment.getDeptName());
//            }
//
//            //考核条例
//            InspectionRegulationDO regulation = regulationMap.get(event.getRegulationId());
//            if (Objects.nonNull(regulation)) {
//                event.setRegulationName(regulation.getRegulationName());
//                event.setRegulationContent(regulation.getRegulationContent());
//            }
//
//
//        }
//
//        return eventPage;
//    }


    @Override
    public Page<InspectionEventDO> pageEvent(InspectionEventQueryDTO page) {
        Sort sort = SortHelper.buildSort(page);
        PageHelper check = PageHelper.check(page.getPageNo(), page.getPageSize());
        Pageable pageable = PageRequest.of(check.getOffset(), check.getPageSize(), sort);


        Page<InspectionEventDO> eventPage = inspectionEventDao.findAll(buildSpecification(page), pageable);


        //对字段进行额外的处理
        for (InspectionEventDO event : eventPage.getContent()) {
            String inspectDeptDetail = event.getInspectDeptDetail();
            if (!StringUtils.isEmpty(inspectDeptDetail)) {
                List<InspectionDepartmentDO> departmentDOS = JSONObject.parseArray(inspectDeptDetail, InspectionDepartmentDO.class);
                event.setInspectDeptName(departmentDOS.stream().map(d -> d.getDeptName()).collect(Collectors.joining(",")));
            }

        }

        return eventPage;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delEvent(InspectionEventDTO del) {
        //直接硬删除
        AssertUtils.nonNull(del.getId(), "事件id不能为空！");
        inspectionEventDao.deleteById(del.getId());
        //删除事件关联表


        inspectionEventDeptRelationDao.deleteByInspectionEventId(del.getId());
    }

    @Override
    public void updateEvent(InspectionEventDTO update) {
        AssertUtils.nonNull(update.getId(), "事件id不能为空！");
        Optional<InspectionEventDO> eventOp = inspectionEventDao.findById(update.getId());
        if (!eventOp.isPresent()) {
            throw new BusinessBaseException("事件不能为空！");
        }
        InspectionEventDO event =eventOp.get();
        event.setEventContent(update.getEventContent());
        event.setInspectScore(update.getInspectScore());
        event.setInspectDesc(update.getInspectDesc());
        event.setRemark(update.getRemark());
        inspectionEventDao.saveAndFlush(event);
    }

    @Override
    public InspectionEventDO getEvent(InspectionEventDTO query) {
        AssertUtils.nonNull(query.getId(), "事件id不能为空！");
        Optional<InspectionEventDO> eventOp = inspectionEventDao.findById(query.getId());
        if (!eventOp.isPresent()) {
            throw new BusinessBaseException("事件不能为空！");
        }
        InspectionEventDO event = eventOp.get();
        //查询被考核的部门列表
        InspectionEventDeptRelationDO eventDeptRelationParam = new InspectionEventDeptRelationDO();
        eventDeptRelationParam.setInspectionEventId(event.getId());
        List<InspectionEventDeptRelationDO> eventDeptRelations = inspectionEventDeptRelationDao.findAll(Example.of(eventDeptRelationParam));

        if(!CollectionUtils.isEmpty(eventDeptRelations)){
            List<Long> exeDeptIds = eventDeptRelations.stream().map(e -> e.getInspectionDeptId()).collect(Collectors.toList());
            event.setInspectDeptList(exeDeptIds);
        }

        return event;
    }

    @Override
    public InspectionEventCorrectDO getEventCorrect(InspectionEventCorrectQueryDTO query) {
        AssertUtils.nonNull(query.getEventId(), "事件id不能为空");

        InspectionEventCorrectDO correctParam = new InspectionEventCorrectDO();
        correctParam.setEventId(query.getEventId());
        Optional<InspectionEventCorrectDO> correctOp = inspectionEventCorrectDao.findOne(Example.of(correctParam));
        if (!correctOp.isPresent()) {
            return null;
        }
        return correctOp.get();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void correctEvent(InspectionEventCorrectDTO correct) {
        //覆盖更新数据   如果不存在 就新增
        InspectionEventCorrectDO correctDO = new InspectionEventCorrectDO();
        BeanUtils.copyProperties(correct, correctDO);
        correctDO.setReportUserId(1L);
        correctDO.setCorrectDate(new Date());

        correctDO.setDateUpdate(new Date());
        if (Objects.isNull(correct.getId())) {
            correctDO.setDateCreate(new Date());
            correctDO.setIsDel(0);
        }
        inspectionEventCorrectDao.saveAndFlush(correctDO);
        //更新
        Optional<InspectionEventDO> eventOp = inspectionEventDao.findById(correct.getEventId());
        if (!eventOp.isPresent()) {
            throw new BusinessBaseException("事件不存在");
        }
        InspectionEventDO eventDO = eventOp.get();
        eventDO.setIsCorrect(correct.getIsCorrect());
        inspectionEventDao.saveAndFlush(eventDO);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelEvent(InspectionEventDTO del) {
        //直接硬删除
        AssertUtils.notEmpty(del.getIdList(), "事件id不能为空！");

        List<InspectionEventDO> events = inspectionEventDao.findAllById(del.getIdList());
        if (CollectionUtils.isEmpty(events)) {
            throw new BusinessBaseException("事件不存在");
        }
        inspectionEventDao.deleteInBatch(events);


        List<Long> eventIdList = events.stream().map(e -> e.getId()).collect(Collectors.toList());
        //删除事件关联表
        List<InspectionEventDeptRelationDO> eventDeptList = inspectionEventDeptRelationDao.findByInspectionEventIdIn(eventIdList);

        if (!CollectionUtils.isEmpty(eventDeptList)) {
            inspectionEventDeptRelationDao.deleteInBatch(eventDeptList);
        }

    }

    @Override
    public void exportEvent(InspectionEventQueryDTO queryDTO, HttpServletResponse response) {


        List<InspectionEventDO> events = inspectionEventDao.findAll(buildSpecification(queryDTO));
        List<InspectionEventExcelVO> vos = new ArrayList<>(events.size());

        for (InspectionEventDO event : events) {
            InspectionEventExcelVO eventExcelVO= new InspectionEventExcelVO();
            BeanUtils.copyProperties(event,eventExcelVO);
            eventExcelVO.setEventCreateDateStr(DateUtil.format(event.getEventCreateDate(),"yyyy-MM-dd HH:mm:ss"));
            eventExcelVO.setEventInspectDateStr(DateUtil.format(event.getEventInspectDate(),"yyyy-MM-dd HH:mm:ss"));
            String inspectDeptDetail = event.getInspectDeptDetail();
            if (!StringUtils.isEmpty(inspectDeptDetail)) {
                List<InspectionDepartmentDO> departmentDOS = JSONObject.parseArray(inspectDeptDetail, InspectionDepartmentDO.class);
                eventExcelVO.setInspectDeptList(departmentDOS.stream().map(d -> d.getDeptName()).collect(Collectors.joining(",")));
            }

            vos.add(eventExcelVO);
        }


        ArrayList<KeyValuePair> pairs = new ArrayList<>();
        pairs.add(KeyValuePair.builder().key("id").value("ID").build());
        pairs.add(KeyValuePair.builder().key("eventCreateDateStr").value("事件发生日期").build());
        pairs.add(KeyValuePair.builder().key("eventInspectDateStr").value("事件考核日期").build());
        pairs.add(KeyValuePair.builder().key("eventContent").value("事件内容").build());
        pairs.add(KeyValuePair.builder().key("inspectScore").value("考核分数").build());
        pairs.add(KeyValuePair.builder().key("inspectDesc").value("考核说明").build());
        pairs.add(KeyValuePair.builder().key("isCorrect").value("是否整改").build());
        pairs.add(KeyValuePair.builder().key("inspectionType").value("考核类型").build());
        pairs.add(KeyValuePair.builder().key("remark").value("备注").build());

        pairs.add(KeyValuePair.builder().key("regulationNo").value("考核编号").build());
        pairs.add(KeyValuePair.builder().key("regulationName").value("考核名称").build());
        pairs.add(KeyValuePair.builder().key("regulationContent").value("考核内容").build());
        pairs.add(KeyValuePair.builder().key("regulationHighestScore").value("考核最高分").build());
        pairs.add(KeyValuePair.builder().key("regulationLowestScore").value("考核最低分").build());
        pairs.add(KeyValuePair.builder().key("inspectBranchName").value("被考核支部").build());

        pairs.add(KeyValuePair.builder().key("executeDeptName").value("考核部门").build());
        pairs.add(KeyValuePair.builder().key("inspectDeptList").value("被考核部门").build());

        ExcelUtils.export("考核事件", vos, pairs, response);


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approveEvent(InspectionEventDTO approve) {
        AssertUtils.nonNull(approve.getId(), "事件id不能为空！");
        Optional<InspectionEventDO> eventOp = inspectionEventDao.findById(approve.getId());
        if (!eventOp.isPresent()) {
            throw new BusinessBaseException("事件不能为空！");
        }
        if (EventApproveStatusEnum.WAIT_APPROVE.getStatus() != eventOp.get().getApproveStatus()) {
            throw new BusinessBaseException("事件不是待审核，无非审核");
        }

        //审核
        InspectionEventDO eventUpdate = eventOp.get();
        eventUpdate.setApproveStatus(EventApproveStatusEnum.APPROVE_STATUS.getStatus());
        inspectionEventDao.saveAndFlush(eventUpdate);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveEvent(InspectionEventDTO save) {
        //校验部分
        Long executeDept = save.getExecuteDept();
        AssertUtils.nonNull(executeDept, "执行部门不能为空！");
        AssertUtils.nonNull(save.getRegulationId(), "执行条例不能为空！");
        AssertUtils.nonNull(save.getInspectScore(), "考核分数不能为空！");

        InspectionDeptRegulationDO deptRegulation = new InspectionDeptRegulationDO();
        deptRegulation.setDeptId(executeDept);
        List<InspectionDeptRegulationDO> allRegulations = inspectionDeptRegulationDao.findAll(Example.of(deptRegulation));
        List<Long> regulationIds = allRegulations.stream().map(m -> m.getRegulationId()).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(regulationIds) || !regulationIds.contains(save.getRegulationId())) {
            throw new BusinessBaseException("该执行部门没有该条例的权限！");
        }

        //获取条例详情
        InspectionRegulationDO regulation = inspectionRegulationDao.getOne(save.getRegulationId());
        AssertUtils.nonNull(regulation, "执行条例不存在！");

        //匹配最高分和最低分
        if (save.getInspectScore() > regulation.getHighestScore() || save.getInspectScore() < regulation.getLowestScore()) {
            throw new BusinessBaseException("考核分数超过阈值！");
        }

        InspectionEventDO eventDO = new InspectionEventDO();
        BeanUtils.copyProperties(save, eventDO);
        eventDO.setApproveStatus(EventApproveStatusEnum.WAIT_APPROVE.getStatus());
        eventDO.setId(null);
        eventDO.setDateCreate(new Date());


        //=====

        //事件快照部分
        eventDO.setRegulationNo(regulation.getRegulationNo());
        eventDO.setRegulationName(regulation.getRegulationName());
        eventDO.setRegulationContent(regulation.getRegulationContent());
        eventDO.setRegulationHighestScore(regulation.getHighestScore());
        eventDO.setRegulationLowestScore(regulation.getLowestScore());


        Optional<InspectionBranchDO> insBranch = inspectionBranchDao.findById(save.getInspectBranch());
        if (insBranch.isPresent()) {
            eventDO.setInspectBranchName(insBranch.get().getBranchName());
        }
        Optional<InspectionDepartmentDO> exeDept = inspectionDepartmentDao.findById(save.getExecuteDept());

        if (exeDept.isPresent()) {
            eventDO.setExecuteDeptName(exeDept.get().getDeptName());
        }
        //考核的部門快照
        List<InspectionDepartmentDO> depts = inspectionDepartmentDao.findAllById(save.getInspectDeptList());
        eventDO.setInspectDeptDetail(JSONObject.toJSONString(depts));
        eventDO.setIsCorrect(YesNoEnum.NO.getVal());
        InspectionEventDO inspectionEventDO = inspectionEventDao.saveAndFlush(eventDO);
        InspectionEventDeptRelationDO relationDO = new InspectionEventDeptRelationDO();
        relationDO.setInspectionEventId(inspectionEventDO.getId());
        for (Long aLong : save.getInspectDeptList()) {
            relationDO.setInspectionDeptId(aLong);
            inspectionEventDeptRelationDao.saveAndFlush(relationDO);
        }


    }


    protected Specification<InspectionEventDO> buildSpecification(InspectionEventQueryDTO page) {


        return (Specification<InspectionEventDO>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            if (Objects.nonNull(page.getExecuteDept())) {
                predicates.add(criteriaBuilder.equal(root.get("executeDept"), page.getExecuteDept()));
            }

            if (Objects.nonNull(page.getInspectScore())) {
                predicates.add(criteriaBuilder.equal(root.get("inspectScore"), page.getInspectScore()));
            }
            if (!StringUtils.isEmpty(page.getEventContent())) {
                predicates.add(criteriaBuilder.like(root.get("eventContent"), "%" + page.getEventContent() + "%"));
            }
            

            if (!StringUtils.isEmpty(page.getExecuteDeptName())) {
                predicates.add(criteriaBuilder.like(root.get("executeDeptName"), "%" + page.getExecuteDeptName() + "%"));
            }
            if (Objects.nonNull(page.getInspectBranch())) {
                predicates.add(criteriaBuilder.equal(root.get("inspectBranch"), page.getInspectBranch()));
            }
            if (!StringUtils.isEmpty(page.getInspectBranchName())) {
                predicates.add(criteriaBuilder.like(root.get("inspectBranchName"),"%"+ page.getInspectBranchName()+"%"));
            }
            if (Objects.nonNull(page.getEventCreateDate())) {
                predicates.add(criteriaBuilder.equal(root.get("eventCreateDate"), page.getEventCreateDate()));
            }
            if (Objects.nonNull(page.getEventCreateDateStart())) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("eventCreateDate"), page.getEventCreateDateStart()));
            }
            if (Objects.nonNull(page.getEventCreateDateEnd())) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("eventCreateDate"), page.getEventCreateDateEnd()));
            }

            if (Objects.nonNull(page.getEventInspectDate())) {
                predicates.add(criteriaBuilder.equal(root.get("eventInspectDate"), page.getEventInspectDate()));
            }
            if (Objects.nonNull(page.getEventInspectDateStart())) {
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("eventInspectDate"), page.getEventInspectDateStart()));
            }
            if (Objects.nonNull(page.getEventInspectDateEnd())) {
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("eventInspectDate"), page.getEventInspectDateEnd()));
            }

            if (Objects.nonNull(page.getRegulationId())) {
                predicates.add(criteriaBuilder.equal(root.get("regulationId"), page.getRegulationId()));
            }
            if (Objects.nonNull(page.getIsCorrect())) {
                predicates.add(criteriaBuilder.equal(root.get("isCorrect"), page.getIsCorrect()));
            }

            if (!StringUtils.isEmpty(page.getRegulationNo())) {
                predicates.add(criteriaBuilder.equal(root.get("regulationNo"), page.getRegulationNo()));
            }
            if (!StringUtils.isEmpty(page.getInspectionType())) {
                predicates.add(criteriaBuilder.equal(root.get("inspectionType"), page.getInspectionType()));
            }


            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        } ;
    }
}
